
// 17.25 in 802.1D-2004
//
// We were supposed to implement the Bridge Detection state machine from 802.1t-2001 (18.2),
// but that would have unnecessarily introduced variables such as macOperational and bpduRcvd,
// Plus, it was superseeded and improved in later standards anyway.

#include "802_1w_2001_procedures.h"
#include "bridge.h"
#include "port.h"
#include "assert.h"

enum
{
	UNDEFINED,
	EDGE,
	NOT_EDGE,
};

// ============================================================================

const char* BridgeDetection_802_1w_2001_GetStateName (SM_STATE state)
{
	switch (state)
	{
		case EDGE:		return "EDGE";
		case NOT_EDGE:	return "NOT_EDGE";
		default:		return "(undefined)";
	}		
}

// ============================================================================

SM_STATE BridgeDetection_802_1w_2001_CheckConditions (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];

	// ------------------------------------------------------------------------
	// Check global conditions.
	
	if (bridge->BEGIN && port->AdminEdge)
	{
		if (state == EDGE)
		{
			// The entry block for this state has been executed already.
			return 0;
		}
		
		return EDGE;
	}
	
	if (bridge->BEGIN && !port->AdminEdge)
	{
		if (state == NOT_EDGE)
		{
			// The entry block for this state has been executed already.
			return 0;
		}
		
		return NOT_EDGE;
	}
	
	// ------------------------------------------------------------------------
	// Check exit conditions from each state.
	
	if (state == EDGE)
	{
		if ((!port->portEnabled && !port->AdminEdge) || !port->operEdge)
			return NOT_EDGE;
		
		return 0;
	}
	
	if (state == NOT_EDGE)
	{
		// from aq-seaman-fragile-bridges-0908.pdf:
		// b) Because BDM is specified in 802.1D I am not sure
		//    that it is clear that it uses proposing for the CIST as
		//    opposed to any other tree.
		if ((!port->portEnabled && port->AdminEdge)
			|| ((port->edgeDelayWhile == 0) && port->AutoEdge && port->sendRSTP && port->trees [CIST_INDEX]->proposing))
		{
			return EDGE;
		}
		
		return 0;
	}
	
	assert (false);
	return 0;
}

// ============================================================================

void BridgeDetection_802_1w_2001_InitState (BRIDGE* bridge, int givenPort, int givenTree, SM_STATE state)
{
	assert (givenPort != -1);
	assert (givenTree == -1);

	PORT* port = bridge->ports [givenPort];

	// ------------------------------------------------------------------------
	
	if (state == EDGE)
	{
		port->operEdge = true;
	}
	else if (state == NOT_EDGE)
	{
		port->operEdge = false;
	}
	else
		assert (false);
}
